package com.evil.formula.service.impl;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.evil.formula.enums.FunctionEnum;
import com.evil.formula.util.FormulaUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author liyang
 * @date 2023-11-01 16:25
 */
@Slf4j
public class FormulaFunction {

    private static final String[] CN_UPPER_NUMBER = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
    private static final String[] CN_UPPER_UNIT = {"", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿"};

    /**
     * if表达式
     *
     * @param test   布尔值
     * @param value1 value1
     * @param value2 value2
     * @return Object
     */
    public static Object funcIf(Object test, Object value1, Object value2) {
        test = ObjectUtil.defaultIfNull(test, Boolean.FALSE);
        return BooleanUtil.toBoolean(test.toString()) ? value1 : value2;
    }

    /**
     * 把字符串串起来
     *
     * @param values values
     * @return String
     */
    public static String funcConcat(Object... values) {
        return Arrays.stream(values).map(e -> ObjectUtil.defaultIfNull(e, "").toString()).collect(Collectors.joining(""));
    }

    /**
     * 取左边的n个数
     *
     * @param value value
     * @param n     n
     * @return String
     */
    public static String funcLeft(Object value, Object n) {
        FormulaUtil.checkValueType(Integer.class, FunctionEnum.LEFT, 0, n);
        String string = ObjectUtil.defaultIfNull(value, "").toString();
        int i = Integer.parseInt(n.toString());
        return string.substring(0, i);
    }

    /**
     * 取右边的n个数
     *
     * @param value value
     * @param n     n
     * @return String
     */
    public static String funcRight(Object value, Object n) {
        FormulaUtil.checkValueType(Integer.class, FunctionEnum.RIGHT, 0, n);
        String string = ObjectUtil.defaultIfNull(value, "").toString();
        int i = Integer.parseInt(n.toString());
        return string.substring(i);
    }

    /**
     * 取代从start开始的长度为n的位置的字符串（注意，用户使用时，第一个位置是1，而不是0）
     *
     * @param value    value
     * @param start    start
     * @param n        n
     * @param newValue newValue
     * @return String
     */
    public static String funcReplace(Object value, Object start, Object n, Object newValue) {
        String str = ObjectUtil.defaultIfNull(value, "").toString();
        String newStr = ObjectUtil.defaultIfNull(newValue, "").toString();
        FormulaUtil.checkValueType(Integer.class, FunctionEnum.REPLACE, 1, start, n);
        int s = Integer.parseInt(start.toString());
        int i = Integer.parseInt(n.toString());
        return str.substring(0, s - 1) + newStr + str.substring(s + i - 1);
    }

    /**
     * 取中间的子串，从start开始，取长度为n的子串
     *
     * @param value value
     * @param start start
     * @param n     n
     * @return String
     */
    public static String funcMid(Object value, Object start, Object n) {
        String str = ObjectUtil.defaultIfNull(value, "").toString();
        int s = Integer.parseInt(start.toString());
        int i = Integer.parseInt(n.toString());
        return str.substring(s - 1, i);
    }

    /**
     * 把时间转化为字符串
     * 将字段转化为特定格式。<br>
     * 1.将日期字段转化为指定展示格式<br>
     * 年月日时分秒对应： yyyy, MM, DD, HH, mm, ss<br>
     * 例如：格式是“YYYYMMDD HH: mm: ss” 转化结果为： 20180101 12: 12: 12<br>
     * 转化结果为： 20180101 12: 12: 12<br>
     * 2.将日期字段转化为星期格式<br>
     * E, EE, EEE表示星期的不同格式，<br>
     * 分别对应0~6，周日~周六，星期日~星期六
     *
     * @param value      value
     * @param timeFormat timeFormat
     * @return String
     */
    public static String funcText(Object value, String timeFormat) {
        FormulaUtil.checkParamCount("TEXT", 2, value, timeFormat);
        switch (timeFormat) {
            case "E" -> {
                return DateTimeFormatter.ofPattern("e").format(LocalDateTime.parse(value.toString()));
            }
            case "EE" -> {
                return DateTimeFormatter.ofPattern("EEE").format(LocalDateTime.parse(value.toString()));
            }
            case "EEE" -> {
                return DateTimeFormatter.ofPattern("EEEE").format(LocalDateTime.parse(value.toString()));
            }
            default -> {
                LocalDateTime t = LocalDateTime.parse(value.toString(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                return t.format(DateTimeFormatter.ofPattern(timeFormat));
            }
        }
    }

    /**
     * 连接单值、多值字段
     *
     * @param connector connector
     * @param arguments arguments
     * @return String
     */
    public static String funcJoin(String connector, Object... arguments) {
        Object[] args = new Object[arguments.length - 1];
        System.arraycopy(arguments, 1, args, 0, arguments.length - 1);
        List<String> valueArray = new ArrayList<>();

        // 最少得有2个参数
        FormulaUtil.checkParamCount("JOIN", 2, args);

        for (Object queValue : args) {
            if (queValue instanceof Object[] queValueArray) {
                valueArray.addAll(Arrays.stream(queValueArray).map(String::valueOf).toList());
            } else {
                valueArray.add(String.valueOf(queValue));
            }
        }
        return String.join(connector, valueArray);
    }

    /**
     * 把其他类型的字段转换成数字类型，可以识别浮点类型
     *
     * @param values values
     * @return List
     */
    public static List<BigDecimal> funNum(Object... values) {
        List<BigDecimal> numList = new ArrayList<>();
        for (Object value : values) {
            if (value instanceof Object[] valueArray) {
                for (Object val : valueArray) {
                    numList.add(FormulaUtil.getFirstNum(String.valueOf(val)));
                }
            } else {
                numList.add(FormulaUtil.getFirstNum(String.valueOf(value)));
            }
        }
        return numList;
    }

    /**
     * 数字转化为人民币大写形式
     *
     * @param value value
     * @return String
     */
    public static String numberToChinese(String value) {
        if (StringUtils.isBlank(value)) {
            return "";
        }
        BigDecimal bd = null;
        try {
            bd = new BigDecimal(value);
        } catch (Exception e) {
            return "";
        }
        String numberStr = bd.toPlainString();
        String[] numArray = numberStr.split("\\.");
        long integerPart = Long.parseLong(numArray[0]);

        StringBuilder sb = new StringBuilder();

        int unitPos = 0;
        boolean needZero = false;
        while (integerPart > 0) {
            long part = integerPart % 10;
            if (part == 0) {
                if (needZero) {
                    sb.insert(0, CN_UPPER_NUMBER[(int) part]);
                }
                needZero = false;
            } else {
                sb.insert(0, CN_UPPER_NUMBER[(int) part] + CN_UPPER_UNIT[unitPos]);
                needZero = true;
            }
            unitPos++;
            integerPart /= 10;
        }

        sb.append("元");
        if (numArray.length > 1) {
            String decimalPart = numArray[1];
            for (int i = 0; i < decimalPart.length(); i++) {
                int digit = Integer.parseInt(String.valueOf(decimalPart.charAt(i)));
                if (digit != 0) {
                    sb.append(CN_UPPER_NUMBER[digit]).append(CN_UPPER_UNIT[i + 1]);
                }
            }
        }

        if (sb.toString().startsWith("壹拾")) {
            sb = new StringBuilder(sb.toString().replaceFirst("壹拾", "拾"));
        }

        return sb.toString();
    }

    /**
     * 数组中null或者undefined的值替换为0
     *
     * @param values values
     * @return BigDecimal
     */
    public static BigDecimal funcSum(Object... values) {
        List<Object> valueList = new ArrayList<>();
        for (Object value : values) {
            if (value instanceof Object[]) {
                valueList.addAll(Arrays.asList((Object[]) value));
            } else {
                valueList.add(value);
            }
        }
        if (valueList.isEmpty()) {
            return BigDecimal.ZERO;
        }
        valueList = FormulaUtil.replaceNullParam(valueList);
        FormulaUtil.checkValueType(BigDecimal.class, FunctionEnum.SUM, 0, valueList.toArray());
        BigDecimal sum = BigDecimal.ZERO;
        for (Object value : valueList) {
            sum = sum.add(new BigDecimal(value.toString()));
        }
        return sum;
    }
}
